
#include <omp.h>
#include <iostream>
#include <cmath>
#include <list>
#include <tuple>
//#include <chrono>
#include <cstdlib>
 
#include "data_format.hpp"
#include "data_output.hpp"
#include "function.hpp"
#include "integral_calc.hpp"

void calc_test(std::list<trip_t>&, Interval_t&, double, size_t, bool);

int main(int argc, char* argv[]){
  freopen("input.txt", "r", stdin);

  size_t threads_num = (argc < 2)? 4 : atoi(argv[1]);

  size_t test_count = 0;
  Interval_t main_interval;
  double param = 0;
  std::list<double> increase_count_list;

  std::cin >> main_interval.inf;
  std::cin >> main_interval.sup;
  std::cin >> param;
  std::cin >> test_count;

  for(int i = 0; i < test_count; ++i){
    double calc_param = 0;
    std::cin >> calc_param;
    increase_count_list.push_back((calc_param >=1)? calc_param : 1.0 / calc_param);
  }

  std::cout << "MAX threads num: " << omp_get_max_threads() << '\n';
  omp_set_num_threads(threads_num);
#pragma omp parallel master
  std::cout << "Threads num in parallel area: " << omp_get_num_threads() << '\n';

#pragma omp parallel 
  {
    #pragma omp critical 
      std::cout << "Number of each thread: " << omp_get_thread_num() << '\n';
  }

  std::endl(std::cout);
  bool mode = false;
  do{
    if(!mode)
// Static schedule, chunk = 10, 100, 1000 
      std::cout << "Schedule: static\n";
    else 
// Dynamic schedule, chunk = 10, 100, 1000
      std::cout << "Schedule: dynamic\n";


    for(int j = 10; j <= 1000; j *= 10){
      std::cout << "Chunk: " << j << '\n';
      
      std::list<trip_t> integral_list;
      for(int i = 0; i < test_count; ++i){
        main_interval.increase_count = increase_count_list.front();
        increase_count_list.push_back(increase_count_list.front());
        increase_count_list.pop_front();

        calc_test(integral_list, main_interval, param, j, mode);
      }
      print_table_2(integral_list);
    }
    
    mode = !mode; 
  }while(mode);

  return 0;
}

void calc_test(std::list<trip_t>& integral_list, Interval_t& main_interval, double param, size_t chunk,bool flag){
  double integral_val = 0;


  //auto t_start = std::chrono::high_resolution_clock::now();
  double t_start = omp_get_wtime();

  integral_val = integral_calc(param, main_interval, chunk, flag);

  double exact_val = primal(main_interval.sup, param) - primal(main_interval.inf, param);
  double err = fabsl(integral_val - exact_val) / fabsl(integral_val);

  //const auto t_end = std::chrono::high_resolution_clock::now();
  //double difftime = std::chrono::duration<double>(t_end - t_start).count();
  double difftime = omp_get_wtime() - t_start;

  integral_list.push_back(std::make_tuple(main_interval.increase_count, err, difftime));

}
